package gang.org.springframework.framework.context;

import gang.org.springframework.framework.beanfactorypostprocessor.GangBeanFactoryPostProcessor;
import gang.org.springframework.framework.core.io.GangResourcePatternResolver;
import gang.org.springframework.framework.core.io.support.GangPathMatchingResourcePatternResolver;
import gang.org.springframework.framework.event.GangApplicationEventMulticaster;
import gang.org.springframework.framework.event.GangSimpleApplicationEventMulticaster;
import gang.org.springframework.framework.factory.GangBeanFactory;
import gang.org.springframework.framework.factory.GangConfigurableListableBeanFactory;
import gang.org.springframework.framework.io.GangDefaultResourceLoader;
import gang.org.springframework.framework.io.GangResource;
import gang.org.springframework.framework.messagesource.GangDelegatingMessageSource;
import gang.org.springframework.framework.messagesource.GangMessageSource;
import gang.org.springframework.framework.support.GangApplicationContextAwareProcessor;
import gang.org.springframework.framework.support.GangApplicationListenerDetector;
import gang.org.springframework.framework.support.GangPostProcessorRegistrationDelegate;
import gang.org.springframework.framework.support.GangResolvableType;

import java.util.*;

/**
 * @author gang.chen
 * @description
 * @Date 2021/6/11 8:45
 */
public abstract class GangAbstractApplicationContext extends GangDefaultResourceLoader implements GangConfigurableApplicationContext {

    private GangMessageSource messageSource;

    private GangApplicationEventMulticaster applicationEventMulticaster;

    public static final String MESSAGE_SOURCE_BEAN_NAME = "messageSource";

    public static final String APPLICATION_EVENT_MULTICASTER_BEAN_NAME="applicationEventMulticaster";

    private final List<GangBeanFactoryPostProcessor> beanFactoryPostProcessors = new ArrayList<>();

    private final Set<GangApplicationListener<?>> applicationListeners = new LinkedHashSet<>();

    private GangResourcePatternResolver resourcePatternResolver;

    public GangAbstractApplicationContext(){
        this.resourcePatternResolver = getResourcePatternResolver();
    }

    @Override
    public void refresh() {
        prepareRefresh();

        GangConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

        prepareBeanFactory(beanFactory);

        try {
            postProcessBeanFactory(beanFactory);

            //###############################################
            // 业务意义
            // 1）启动BeanFactoryPostProcessor接口实现类
            // 2）自动装配类封装为BeanDefinition
            //###############################################
            invokeBeanFactoryPostProcessor(beanFactory);


            //###############################################
            // 业务意义
            // 1）注册bean processor 它可以拦截 bean 的创建
            //###############################################
            registerBeanPostProcessors(beanFactory);

            //###############################################
            // 业务意义
            //1）初始化 messageSource bean
            //###############################################
            initMessageSource();

            //###############################################
            // 业务意义
            // 初始化 GangSimpleApplicationEventMulticaster bean
            //###############################################
            initApplicationEventMulticaster();

            //###############################################
            // 业务意义
            // 被子类来实现，针对MVC由 ServletWebServerApplicationContext实现
            // TODO
            //###############################################
            onRefresh();

            //###############################################
            // 业务意义
            // 1）ApplicationContextInitializer 初始化监听器
            // 2）ApplicationListener 初始化监听器
            //###############################################
            registerListeners();

            //###############################################
            // 业务意义
            // 1）实例化所有剩余的非懒加载单例
            //###############################################
            finishBeanFactoryInitialization(beanFactory);

            finishRefresh();
            System.out.println("GangAbstractApplicationContext->refresh()-> end...");
        }
        catch (Exception e){
            e.printStackTrace();
        }
    }

    @Override
    public abstract GangConfigurableListableBeanFactory getBeanFactory();


    protected void prepareRefresh(){
    }

    protected GangConfigurableListableBeanFactory obtainFreshBeanFactory(){
        return getBeanFactory();
    }

    /**
     * @param beanFactory spring BeanFactory
     * */
    protected void prepareBeanFactory(GangConfigurableListableBeanFactory beanFactory){

        beanFactory.registerResolvaleDependency(GangBeanFactory.class, beanFactory);

        beanFactory.addBeanPostProcessor(new GangApplicationListenerDetector(this));

        beanFactory.addBeanPostProcessor(new GangApplicationContextAwareProcessor(this));

    }

    protected void postProcessBeanFactory(GangConfigurableListableBeanFactory beanFactory){

    }

    /**
     * TODO
     * @param beanFactory {@link gang.org.springframework.framework.factory.GangDefaultListableBeanFactory}
     * */
    protected void invokeBeanFactoryPostProcessor(GangConfigurableListableBeanFactory beanFactory){
        GangPostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory,getBeanFactoryPostProcessors());
    }

    /**
     * TODO
     * @param beanFactory {@link gang.org.springframework.framework.factory.GangDefaultListableBeanFactory}
     * */
    protected void registerBeanPostProcessors(GangConfigurableListableBeanFactory beanFactory){
        GangPostProcessorRegistrationDelegate.registerBeanPostProcessors(beanFactory,this);
    }

    protected void initMessageSource(){
        //TODO
        GangConfigurableListableBeanFactory beanFactory = getBeanFactory();
        GangDelegatingMessageSource dms = new GangDelegatingMessageSource();
        this.messageSource = dms;
        beanFactory.registerSingleton(MESSAGE_SOURCE_BEAN_NAME,this.messageSource);

    }

    protected void initApplicationEventMulticaster(){
        GangConfigurableListableBeanFactory beanFactory = getBeanFactory();
        this.applicationEventMulticaster = new GangSimpleApplicationEventMulticaster(beanFactory);
        beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME,this.applicationEventMulticaster);
    }

    protected void onRefresh(){

    }

    /**
     * 场景一 静态13个监听器
     * 00 = {RSocketPortInfoApplicationContextInitializer$Listener@8998}
     *  -该类实现两个接口
     *  -ApplicationContextInitializer
     *  -ApplicationListener
     * 01 = {ServerPortInfoApplicationContextInitializer@8999}
     *  -该类实现两个接口
     *  -ApplicationContextInitializer
     *  -ApplicationListener
     * 02 = {ConditionEvaluationReportLoggingListener$ConditionEvaluationReportListener@9000}
     * 03 = {EnvironmentPostProcessorApplicationListener@9001}
     * 04 = {AnsiOutputApplicationListener@9002}
     * 05 = {LoggingApplicationListener@9003}
     * 06 = {BackgroundPreinitializer@9004}
     * 07 = {DelegatingApplicationListener@9005}
     * 08 = {ParentContextCloserApplicationListener@9006}
     * 09 = {ClearCachesApplicationListener@9007}
     * 10 = {FileEncodingApplicationListener@9008}
     * 11 = {SpringApplicationShutdownHook$ApplicationContextClosedListener@9009}
     * 12 = {SharedMetadataReaderFactoryContextInitializer$SharedMetadataReaderFactoryBean@9010}
     *
     * 场景二
     * 0 = "&org.springframework.boot.autoconfigure.internalCachingMetadataReaderFactory"
     * 1 = "mvcResourceUrlProvider"
     *  1.1-ResourceUrlProvider
     *  1.2-WebMvcConfigurationSupport
     *  1.3-EnableWebMvcConfiguration
     *  1.4-WebMvcAutoConfiguration
     *  1.5-WebMvcAutoConfigurationAdapter
     * 2 = "springApplicationAdminRegistrar"
     * 3 = "applicationAvailability"
     * */
    protected void registerListeners(){
        /**
         * 业务场景一
         * 注册静态特殊监听器，这些监听器来自两个接口的实现类，在工厂配置文件spring.factories直接配置
         * 1.1 ApplicationContextInitializer
         * 1.2 ApplicationListener
         * */
        for (GangApplicationListener<?> applicationListener : getApplicationListeners()) {
            getApplicationEventMulticaster().addApplicationListener(applicationListener);
        }

        /**
         * 业务场景二
         * 业务意义，从BeanDefinitions中获取，获取实现了GangApplicationListener接口的类
         * 1.1 GangApplicationListener获取的目标对象
         * 1.2 返回结果为：接口GangApplicationListener实现Bean名
         * */
        String[] listenerBeanNames = getBeanNamesForType(GangApplicationListener.class, true, false);
        for (String listenerBeanName : listenerBeanNames) {
            getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);
        }

        /**
         * 业务场景三
         * 暂不编码
         * */
        //TODO
    }

    protected void finishBeanFactoryInitialization(GangConfigurableListableBeanFactory beanFactory)
    {
        //初始化转换service为上下文 TODO

        //注册一个默认值 TODO

        //初始化 LoadTimeWeaverAware bean对象 TODO

        //停止使用临时类加载器

        //允许cache存储beanDefinition, 不期望有窜改 TODO

        //实例化非懒加载单例bean
        beanFactory.preInstantiatedSingletons();
    }

    protected void finishRefresh(){

    }

    /**
     * 业务意义
     * 1）type为输入参数E.g GangApplicationListener.class，返回该接口实现类Bean名字
     * */
    @Override
    public String[] getBeanNamesForType(Class type, boolean includeNonSingletons, boolean allowEagerInit) {
        return getBeanFactory().getBeanNamesForType(type, includeNonSingletons, allowEagerInit);
    }

    //TODO
    public List<GangBeanFactoryPostProcessor> getBeanFactoryPostProcessors(){
        return null;
    }

    //TODO
    @Override
    public <T> T getBean(String name, Class<T> requiredType) {
        return null;
    }

    //TODO
    @Override
    public String[] getBeanDefinitionNames() {
        return null;
    }

    @Override
    public void addApplicationListener(GangApplicationListener<?> listener) {
        this.applicationListeners.add(listener);
    }

    GangApplicationEventMulticaster getApplicationEventMulticaster(){
        return this.applicationEventMulticaster;
    }

    public Collection<GangApplicationListener<?>> getApplicationListeners() {
        return applicationListeners;
    }

    @Override
    public boolean isTypeMatch(String name, Class<?> typeToMatch) {
        return false;
    }

    @Override
    public boolean isTypeMatch(String name, GangResolvableType typeToMatch) {
        return false;
    }

    @Override
    public GangResource[] getResources(String locationPattern) {
        return this.resourcePatternResolver.getResources(locationPattern);
    }

    protected GangResourcePatternResolver getResourcePatternResolver(){
        return new GangPathMatchingResourcePatternResolver(this);
    }

    @Override
    public <T> Map<String, T> getBeansOfType(Class<T> type, boolean includeNonSingletons, boolean allowEagerInit) {
        //TODO

        return getBeanFactory().getBeansOfType(type, includeNonSingletons, allowEagerInit);
    }
}
